package com.xbk.seckill.common.lock.redisson;

import com.xbk.seckill.common.lock.DistributedLock;
import com.xbk.seckill.common.lock.factory.DistributedLockFactory;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * 基于Redisson的分布式锁实现服务
 *
 * @author xiexu
 * @date 2025/1/31 12:12
 */
@Slf4j
@Component
@ConditionalOnProperty(name = "distributed.lock.type", havingValue = "redisson")
public class RedissonLockFactory implements DistributedLockFactory {

    @Autowired
    private RedissonClient redissonClient;

    /**
     * 根据key获取分布式锁实例
     *
     * @param key
     * @return
     */
    @Override
    public DistributedLock getDistributedLock(String key) {
        RLock rLock = redissonClient.getLock(key);
        return new DistributedLock() {

            /**
             * 尝试在指定时间内获取锁，如果成功获取，则自动在指定时间后释放锁
             * @param waitTime  尝试获取锁的最大等待时间
             * @param leaseTime 成功获取锁后，锁持有的时间
             * @param unit      时间单位
             * @return
             * @throws InterruptedException
             */
            @Override
            public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {
                boolean isLockSuccess = rLock.tryLock(waitTime, leaseTime, unit);
                log.info("{} get lock result:{}", key, isLockSuccess);
                return isLockSuccess;
            }

            /**
             * 尝试立即获取锁（不等待）
             * @return
             * @throws InterruptedException
             */
            @Override
            public boolean tryLock() throws InterruptedException {
                return rLock.tryLock();
            }

            /**
             * 获取锁并指定锁的持有时间
             * @param leaseTime 锁持有的时间
             * @param unit      时间单位
             */
            @Override
            public void lock(long leaseTime, TimeUnit unit) {
                rLock.lock(leaseTime, unit);
            }

            /**
             * 释放锁
             */
            @Override
            public void unlock() {
                // 释放锁前先判断当前线程是否持有锁，避免异常
                if (isLocked() && isHeldByCurrentThread()) {
                    rLock.unlock();
                }
            }

            /**
             * 判断锁是否被任意线程持有
             * @return
             */
            @Override
            public boolean isLocked() {
                return rLock.isLocked();
            }

            /**
             * 判断指定线程是否持有该锁
             * @param threadId
             * @return
             */
            @Override
            public boolean isHeldByThread(long threadId) {
                return rLock.isHeldByThread(threadId);
            }

            /**
             * 判断当前线程是否持有该锁
             * @return
             */
            @Override
            public boolean isHeldByCurrentThread() {
                return rLock.isHeldByCurrentThread();
            }
        };
    }
}
